<?php

/**
 * Cписок в бэкенде.
 *
 */
class Backend_Component_List extends Kernel_Action_List {

    /**
     * Наименования действий, которые могут быть выполнены над элементом списка.
     *
     * @var array
     */
    public $actions = array();

    /**
     * Путь к файлу шаблона.
     *
     * @var string
     */
    protected $_template = 'backend/component/list.tpl';

    /**
     * Если указана таблица, в которой храниятся элементы списка, то
     * компонент автоматически строит запросы для выборки данных.
     *
     * @var string
     */
    protected $_table;

    /**
     * Наименования колонок списка.
     *
     * @var array
     */
    protected $_columns = array();

    /**
     * Описание первичного ключа таблицы.
     *
     * @var mixed
     */
    protected $_key;

    /**
     * Условие выборки записей.
     *
     * @var string
     */
    protected $_where;

    /**
     * Наименование поля, по которому нужно упорядочивать записи.
     *
     * @var string
     */
    protected $_order;

    /**
     * Проекция наименований полей сортировки на выражения, используемые
     * в SQL-запросе.
     *
     * @var array
     */
    protected $_order_map = array();

    /**
     * Наименование параметра URL, в который передается наименование действия.
     * Может быть изменено для вложенных списков.
     *
     * @var string
     */
    protected $_action_param = 'action';

    /**
     * Массив наименований полей списка, для которых порядок вывода записей
     * по умолчанию — обратный.
     *
     * @var array
     */
    protected $_reverse = array();

    /**
     * Направление вывода записей: true — прямое, false — обратное.
     *
     * @var boolean
     */
    private $_direction;

    /**
     * Наименования полей, по которым запрещено упорядочивание записей.
     *
     * @var array
     */
    private $_no_order = array();

    /**
     * Конструктор.
     *
     */
    public function __construct($param = array()) {
        parent::__construct($param);
        $this->_no_order = array_keys(array_filter($this->_order_map, create_function('$value', 'return false === $value;')));
    }

    /**
     * Реализация обработки пользовательского запроса.
     *
     */
    protected function _process() {

        if (empty($this->_columns)) {
            trigger_error('Columns must be specified in class definition', E_USER_ERROR);
        }

        $request = Application::getRequest();

        $this->_order = $request->get('order', null !== ($this->_order)
            ? $this->_order
            : reset($this->_columns));

        if (!in_array($this->_order, $this->_columns) || in_array($this->_order, $this->_no_order)) {
            $this->_abort('Incorrect order specified');
        }

        switch ($request->get('direction')) {
            case 'asc':
                $this->_direction = true;
                break;
            case 'desc':
                $this->_direction = false;
                break;
            default:
                $this->_direction = !in_array($this->_order, $this->_reverse);
                break;
        }

        parent::_process();

        Application::getResponse()->assign('list', array(
            'columns' => $this->_columns,
                'key' => (array)(null !== $this->_key ? $this->_key : reset($this->_columns)),
              'order' => $this->_order,
          'direction' => $this->_direction,
            'actions' => $this->_getActions(),
           'disabled' => $this->_getDisabled(),
            'noorder' => $this->_no_order,
        ));
    }

    /**
     * Формирует запрос выборки записей страницы.
     *
     * @return  string
     */
    protected function _getQueryBody() {

        if (!is_string($this->_table)) {
            trigger_error('Table must be specified in class definition', E_USER_ERROR);
        }

        $query = 'SELECT SQL_CALC_FOUND_ROWS
                         ' . implode(', ', $this->_columns) . '
                    FROM
                         `' . $this->_table . '`' . $this->_getOrder();

        if (!is_null($this->_where)) {
            $query .= '
                   WHERE
                         ' . $this->_where;
        }
        return $query;
    }

    /**
     * Возвращает SQL-выражение для упорядочения записей списка.
     *
     * @return  string
     */
    protected function _getOrder() {
        $order = '';
        if (!is_null($this->_order)) {
            $order .= '
                ORDER BY
                         ' . (isset($this->_order_map[$this->_order])
                ? $this->_order_map[$this->_order]
                : '`' . $this->_order . '`');

            if (!$this->_direction) {
                $order .= ' DESC';
            }
        }
        return $order;
    }

    /**
     * Возвращает описания действий, доступных для выполнения над элементом
     * списка.
     *
     * @return  array
     */
    protected function _getActions() {
        $actions = array();
        foreach ($this->actions as $name => $params) {
            $actions[$name] = empty($params)
                ? array($this->_action_param => $name) : $params;
        }
        return $actions;
    }

    /**
     * Возвращает ассоциативный массив наименований действий и ключей записей,
     * для которых эти действия должны быть запрещены.
     *
     * @return  array
     */
    protected function _getDisabled() {
        return array();
    }
}
